package red.mlz.excelservice.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import red.mlz.common.entity.category.Category;
import red.mlz.excelservice.feign.CategoryFeign;
import red.mlz.excelservice.listener.DynamicExcelListener;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class ExcelController {

    @Autowired
    private CategoryFeign categoryFeign;

    @Autowired
    @Qualifier("exportTaskExecutor")
    private ExecutorService exportTaskExecutor;

    @RequestMapping("/excel/upload")
    public String upload(@RequestPart(name = "file") MultipartFile file,
                           @RequestParam(value = "headerRow", defaultValue = "0") int headerRow) {

        System.out.println("开始处理文件：" + file.getOriginalFilename());
        try (InputStream inputStream = file.getInputStream()) {
            DynamicExcelListener listener = new DynamicExcelListener(headerRow);

            EasyExcel.read(inputStream)
                    .headRowNumber(headerRow)
                    .registerReadListener(listener)
                    .sheet()
                    .doRead();

            System.out.println("处理完成，结果数据：" + listener.getResult());
            return listener.getResult().toString();
        } catch (Exception e) {
            return e.getMessage();
        }
    }

    @RequestMapping("/export/categories")
    public ResponseEntity<byte[]> exportCategories() {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            doExport(outputStream);
            byte[] bytes = outputStream.toByteArray();

            return ResponseEntity.ok()
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=categories.xlsx")
                    .body(bytes);
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(String.format("{\"code\":500,\"message\":\"%s\"}", e.getMessage()).getBytes());
        }
    }

    private void doExport(OutputStream outputStream) throws Exception {
        final int pageSize = 1000;
        long total = categoryFeign.getTotalCount();
        int totalPages = (int) ((total + pageSize - 1) / pageSize);

        try (ExcelWriter excelWriter = EasyExcel.write(outputStream, Category.class)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .build()) {

            WriteSheet writeSheet = EasyExcel.writerSheet("分类数据").build();

            List<CompletableFuture<List<Category>>> futures = new ArrayList<>();
            for (int page = 0; page < totalPages; page++) {
                final int currentPage = page;
                CompletableFuture<List<Category>> future = CompletableFuture.supplyAsync(
                        () -> categoryFeign.getByPage(currentPage, pageSize),
                        exportTaskExecutor
                );
                futures.add(future);
            }

            for (CompletableFuture<List<Category>> future : futures) {
                try {
                    List<Category> data = future.get(30, TimeUnit.SECONDS);
                    excelWriter.write(data, writeSheet);
                } catch (Exception e) {
                    log.error("导出数据时出错", e);
                }
            }
        }

    }
}
